﻿using System;
using Microsoft.Xna.Framework;
using ShevaEngine.Core.Modules.ArtificialIntelligence.Pathfinding;
using ShevaEngine.Core.Modules.Scenes;

namespace ShevaEngine.Core.Modules.ArtificialIntelligence.Tasks
{
    /// <summary>
    /// Follow task.
    /// </summary>
    public class FollowTask : AITask
    {
        /// <summary>Entity to follow.</summary>
        public SceneObject SceneObjectToFollow;
        /// <summary>Navigation graph.</summary>
        private NavigationGraph NavigationGraph;
        /// <summary>Distance squared.</summary>
        private float DistanceSquared;
        /// <summary>Distance.</summary>
        public float Distance { get { return (float)Math.Sqrt(this.DistanceSquared); } set { this.DistanceSquared = value * value; } }
        /// <summary>Navigation path.</summary>
        private NavigationPath NavigationPath;
        /// <summary>Speed.</summary>
        public float Speed;
        /// <summary>Angle speed.</summary>
        public float AngleSpeed;
        /// <summary>Follow task state.</summary>
        private FollowTaskState _State;
        /// <summary>Follow task state.</summary>
        public FollowTaskState State
        {
            get { return this._State; }
            set
            {
                if (value != this._State)
                {
                    this._State = value;

                    if (this.StateChanged != null)
                        this.StateChanged(this, this._State);
                }
            }
        }
        /// <summary>State changed event.</summary>
        public event OnFollowStateChangedCallback StateChanged;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="sceneObject"></param>
        /// <param name="sceneObjectToFollow"></param>
        public FollowTask(SceneObject sceneObject, NavigationGraph navigationGraph, SceneObject sceneObjectToFollow, 
            float distance = 1.0f, float speed = 0.02f, float angleSpeed = 0.03f)
            : base(sceneObject)
        {
            this.NavigationGraph = navigationGraph;
            this.SceneObjectToFollow = sceneObjectToFollow;
            this.Distance = distance;
            this.Speed = speed;
            this.AngleSpeed = angleSpeed;
            this.NavigationPath = new NavigationPath();
            this.State = FollowTaskState.Stand;
        }

        /// <summary>
        /// Method overrides Update.
        /// </summary>
        /// <param name="time"></param>
        public override void Update(GameTime time)
        {
            if (Vector3.DistanceSquared(this.SceneObject.World.Translation, this.SceneObjectToFollow.World.Translation) > this.DistanceSquared)
            {
                if (this.NavigationGraph.FindPath(this.SceneObject.World.Translation, this.SceneObjectToFollow.World.Translation, ref this.NavigationPath))
                    MoveToTask.Move(this.SceneObject, this.NavigationPath, this.Speed, this.AngleSpeed);

                this.State = FollowTaskState.Follow;
            }
            else
                this.State = FollowTaskState.Stand;
        }
    }

    /// <summary>
    /// Follow task state.
    /// </summary>
    public enum FollowTaskState
    {
        Stand,
        Follow
    }

    /// <summary>
    /// On Follow State Changed callback.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="newState"></param>
    public delegate void OnFollowStateChangedCallback(object sender, FollowTaskState newState);
}
